#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <string.h>
#include <sqlite3.h>
#include <signal.h>
#include <time.h>
#include <sys/socket.h>
#include <netinet/in.h>
#include <arpa/inet.h>
 
#define DATABASE "my.db"
#define N 16
 
enum CMD
{
    R = 1,
    L,
    Q,
    H
};
 
typedef struct sockaddr SA;
 
typedef struct
{
    int type;
    char name[N];
    char data[256]; // password or word
} MSG;
 
static sqlite3 *db;
 
/**
 * @brief 服务器处理注册
 * 得到用户输入用户名和密码并拼接sql语句
 * 执行sql语句
 * 封装执行结果并回发客户端
 */
void do_register(int connfd, MSG *pbuf)
{
    char sql[128] = {0};
    char *errmsg;
    sprintf(sql,"insert into usr values ('%s', '%s')", pbuf->name, pbuf->data);
    printf("%s\n", sql);
    if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
    {
        sqlite3_free(errmsg);
        sprintf(pbuf->data,"用户%s已经存在了",pbuf->name); 
    }
    else
    {
        strncpy(pbuf->data, "OK", 256);
    }
    send(connfd, pbuf, sizeof(MSG), 0);
}
 
/**
 * @brief 服务器处理登录
 * 得到用户输入用户名和密码并拼接sql语句
 * 执行sql语句
 * 封装执行结果并回发客户端
 */
void do_login(int connfd, MSG *pbuf)
{
    char sql[128];
    char *errmsg, **result;
   int nrow, ncloum;
 
    sprintf(sql, "select * from usr where  name='%s'and pass ='%s'", pbuf->name, pbuf->data);
    if (sqlite3_get_table(db,sql, &result, &nrow, &ncloum, &errmsg) != SQLITE_OK)
    {
        printf("错误:%s\n", errmsg);
        sqlite3_free(errmsg);
    }
    if (nrow == 0)
    {
        strncpy(pbuf->data, "用户名或者密码错误!!!", 256);
    }
    else
    {
        strncpy(pbuf->data, "OK", 256);
    }
    send(connfd, pbuf, sizeof(MSG), 0);
    sqlite3_free_table(result);
    return;
}
/**
 * @brief 查询单词释义
 * @return 查询成功返回1 失败返回0
 */
int do_searchword(int connfd, MSG *pbuf)
{
    char sql1[128] = {0};
    char *errmsg, **resultp;
    int n_row, n_cloum;
    printf("要查找的单词：%s\n", pbuf->data);
    sprintf(sql1, "select * from dic where word='%s'", pbuf->data);
 
    if (sqlite3_get_table(db, sql1, &resultp, &n_row, &n_cloum, &errmsg) != SQLITE_OK)
    {
        printf("错误:%s\n", errmsg);
        return -1;
    }
    if (n_row != 1)
    {
        return 0;
    }
    char **p;
    p = resultp + n_cloum;
    strcpy(pbuf->data, p[1]);
    return 1;
}
/**
 * @brief 返回当前的时间，存到date中
 * @return 
 */
void get_date(char *date)
{
    time_t t;
    struct tm *tp;
 
    time(&t);
 
    tp = localtime(&t);
    strftime(date, 64, "%Y-%m-%d %H:%M:%S", tp);
 
    return;
}
 
/**
 * @brief 服务器处理查询
 * 查询单词释义
 * 把本次查询添加到查询历史中
 */
void do_query(int connfd, MSG *pbuf)
{
    char sql[128], *errmsg;
    int len, result, found = 0;
    char date[64], word[64];
 
    strcpy(word, pbuf->data);
    found = do_searchword(connfd, pbuf);
    if (found)
    {
         get_date(date);
        sprintf(sql, "insert into record values ('%s','%s','%s')", pbuf->name, date, word);
        if (sqlite3_exec(db, sql, NULL, NULL, &errmsg) != SQLITE_OK)
        {
            printf("错误:%s\n", errmsg);
            sqlite3_free(errmsg);
        }
 
    }
    else
    {
        strcpy(pbuf->data,"没发现单词\n");
    }
    send(connfd,pbuf,sizeof(MSG),0);
    return;
}
 
/**
 * @brief 查询历史处理
 * 根据用户名来查找查询历史，并将结果返回给客户端
 * 执行sql语句
 * 封装执行结果并回发客户端
 */
int history_callback(void *arg, int f_num, char **f_value, char **f_name)
{
    int connfd;
    MSG buf;
 
    connfd = *(int *)arg;
    sprintf(buf.data, "%s : %s", f_value[1], f_value[2]);
    send(connfd, &buf, sizeof(buf), 0);
 
    return 0;
}
 
void do_history(int connfd, MSG *pbuf)
{
    char sqlstr[128], *errmsg;
 
    sprintf(sqlstr, "select * from record where name = '%s'", pbuf->name);
    if (sqlite3_exec(db, sqlstr, history_callback, (void *)&connfd, &errmsg) != SQLITE_OK)
    {
        printf("错误 : %s\n", errmsg);
        sqlite3_free(errmsg);
    }
    pbuf->data[0] = '\0';
    send(connfd, pbuf, sizeof(MSG), 0);
 
    return;
}
 
/**
 * @brief do_client 处理客户端请求
 * @param connfd 客户端fd
 * @param db 数据库句柄
 */
void do_client(int connfd)
{
    MSG buf;
    while (recv(connfd, &buf, sizeof(buf), 0) > 0)
    {
        switch (buf.type)
        {
        case R:
            printf("will reg\n");
            do_register(connfd, &buf);
            break;
        case L:
            printf("will login\n");
            do_login(connfd, &buf);
            break;
        case Q:
            printf("will query\n");
            do_query(connfd, &buf);
            break;
        case H:
            printf("will history\n");
            do_history(connfd, &buf);
            break;
        default:
            break;
        }
    }
 
    exit(0);
}
 
int main(int argc, char *argv[])
{
    int listenfd, connfd;
    struct sockaddr_in myaddr;
    pid_t pid;
    MSG buf;
 
    if (argc < 3)
    {
        printf("Usage : %s <ip> <port>\n", argv[0]);
        exit(-1);
    }
 
    //打开数据库
    if (sqlite3_open(DATABASE, &db) < 0)
    {
        printf("fail to sqlite3_open : %s\n", sqlite3_errmsg(db));
        return -1;
    }
 
    //创建服务器socket
    listenfd = socket(PF_INET, SOCK_STREAM, 0);
    if (listenfd < 0)
    {
        perror("fail to socket");
        exit(-1);
    }
    bzero(&myaddr, sizeof(myaddr));
    myaddr.sin_family = PF_INET;
    myaddr.sin_port = htons(atoi(argv[2]));
    myaddr.sin_addr.s_addr = inet_addr(argv[1]);
    if (bind(listenfd, (SA *)&myaddr, sizeof(myaddr)) < 0)
    {
        perror("fail to bind");
        exit(-1);
    }
 
    // XXX int listen(int sockfd, int backlog);
    if (listen(listenfd, 5) < 0)
    {
        perror("fail to listen");
        exit(-1);
    }
 
    //并发服务器模型
    while (1)
    {
        if ((connfd = accept(listenfd, NULL, NULL)) < 0)
        {
            perror("fail to accept");
            exit(-1);
        }
        pid = fork();
        if (pid == -1)
        {
            perror("fail to fork\n");
            exit(-1);
        }
        else if (pid == 0)
        { //子进程
            printf("a user comming\n");
            do_client(connfd);
        }
        else
        { //父进程
            close(connfd);
        }
    }
}